package wxpay

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	brandService "bgs/service/brand"
	"bgs/util"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
	"strconv"
)

var (
	lastSubMchWithdrawNotification *SubMchWithdrawNotification = nil
)

// SubMchWithdrawNotification - 提现更新通知
type SubMchWithdrawNotification struct {
	// 品牌ID(sg_id)
	BrandID string `json:"brand_id"`
	// 商户号
	MchID string `json:"mch_id"`
	// 子商户号
	SubMchID string `json:"sub_mch_id"`
	// 提现业务单号（本系统）
	OutRequestNo string `json:"out_request_no"`
	// 微信提现ID（微信生成）
	WxWithdrawID string `json:"wx_withdraw_id"`
	// 业务提现ID（业务方生成）
	BizWithdrawID string `json:"biz_withdraw_id"`
	// 提现状态
	// CREATE_SUCCESS：受理成功
	// SUCCESS：提现成功
	// FAIL：提现失败
	// REFUND：提现退票
	// CLOSE：关单
	// INIT：业务单已创建
	Status    string `json:"status"`
	Timestamp int64  `json:"timestamp"`
}

type BrandWithdrawHandler struct {
	dao          *db.PgDao
	slog         *zap.SugaredLogger
	brandService *brandService.BrandServiceImp
}

// NewBrandWithdrawHandler create a new handler for brand withdraw
func NewBrandWithdrawHandler(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	brandService *brandService.BrandServiceImp,
) *BrandWithdrawHandler {
	return &BrandWithdrawHandler{
		dao:          pgdao,
		slog:         slog.With("nsq_consumer_handler", "BrandWithdrawHandler"),
		brandService: brandService,
	}
}

// HandleMessage implements the Handler interface.
func (h *BrandWithdrawHandler) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}
	h.slog.Infof("message=>%s", string(m.Body))

	v := &SubMchWithdrawNotification{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析消息[SubMchWithdrawNotification]: %s", decodeErr.Error())
	}

	if lastSubMchWithdrawNotification != nil && lastSubMchWithdrawNotification.Timestamp >= v.Timestamp {
		h.slog.Infof("过时的消息: lastSubMchWithdrawNotification.Timestamp:%v,v.Timestamp:%v", lastSubMchWithdrawNotification.Timestamp, v.Timestamp)
		return nil
	}
	reqID := strconv.FormatInt(v.Timestamp, 10)
	slog := h.slog.With("reqID", reqID)
	// 将来抽象到对应的业务组件
	ctx := context.WithValue(context.Background(), util.RequestID{}, reqID)

	outRequestNo := v.OutRequestNo
	applyState := v.Status

	var withdrawApplyment sqlc.BrandAccountWithdrawApplyment

	err := h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		withdrawApplyment, err = q.GetBrandAccountWithdrawApplymentByOutRequestNo(ctx, sqlc.NSFromString(outRequestNo))
		if err != nil {
			return
		}
		slog.Infof("a 获取商家提现申请 ok")

		withdrawApplyment, err = h.brandService.UpdateWithdrawApplyment(ctx, q, brandService.UpdateWithdrawApplymentParam{
			BrandAccountWithdrawApplymentPtr: &withdrawApplyment,
			ApplyState:                       applyState,
			WxWithdrawID:                     v.WxWithdrawID,
		})
		if err != nil {
			return
		}
		slog.Infof("b 商家更新提现申请 ok")

		if applyState == "SUCCESS" {
			err = h.brandService.LoggingAccountForWithdraw(ctx, q, &withdrawApplyment)
			if err != nil {
				return
			}
			slog.Infof("c 商家提现记账 ok")
		} else {
			slog.Infof("c 无须商家提现记账(%s) ok", applyState)
		}
		return
	})
	if err != nil {
		return err
	}
	slog.Infof("消息[SubMchWithdrawNotification]处理成功")

	lastSubMchWithdrawNotification = v
	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
